import json
import traceback
from typing import Literal

import requests
from mcp.server.fastmcp import FastMCP
from common.configuration import get_system_settings, get_ruge_settings
from common.doris_connection import DorisConnectionManager
from common.mysql_connection import MySQLConnectionManager
import common.logger as logger
from inspection_rules import get_inspection_rules

mcp = FastMCP("IoT-MCP-Service", port=get_system_settings("web_port"))

# 为了避免数据量过大，限制返回查询到的数据条数
MAX_DATA_SIZE = 10000


@mcp.tool()
async def get_device_info(tenant_id: int, query_str: str) -> list:
    """
    根据搜索关键字，获取设备的具体信息

    参数：
    tenant_id: 租户ID，用于区分数据权限
    query_str: 搜索关键字,包括设备标识码、设备名称、设备编码、设备类型、设备描述等

    返回:
    设备列表，包含了查询到所有设备的具体信息
    具体信息包含的字段如下(括号中的是对应的数据库表的字段名)：
        产品ID(product_id)
        产品标识码(product_key)
        产品名称(product_name)
        协议类型(protocol)
        设备ID(device_id)
        设备标识码(device_name)
        设备编码(device_code)
        设备状态(device_status)
        设备名称(description)
        启用状态(enable_status)
        扩展信息(extend_info)
        激活时间，字符串类型，已转换成用户的可读格式(activation_time)
        创建时间，字符串类型，已转换成用户的可读格式(creation_date)
    """
    try:
        with MySQLConnectionManager.get_connection() as conn:
            with conn.cursor() as cursor:
                sql = f"""
                select
                    p.product_id,
                    p.product_key ,
                    p.product_name ,
                    p.protocol ,
                    d.device_id ,
                    d.device_name ,
                    d.device_code ,
                    d.device_status ,
                    d.description ,
                    d.enable_status ,
                    d.extend_info ,
                    DATE_FORMAT(d.activation_time, '%%Y-%%m-%%d %%H:%%i:%%s') as activation_time,
                    DATE_FORMAT(d.creation_date, '%%Y-%%m-%%d %%H:%%i:%%s') as creation_date
                from
                    ruge_vlink.vlink_device_t_{tenant_id} d,
                    ruge_vlink.vlink_product_t_{tenant_id} p
                where
                    d.product_key = p.product_key
                    and (upper(d.device_name) like upper(%s)
                        or upper(d.description) like upper(%s)
                        or upper(p.product_name) like upper(%s))
                order by d.creation_date asc
                limit 0,{MAX_DATA_SIZE};
                """
                param_str = f'%{query_str}%'
                cursor.execute(sql, (param_str, param_str, param_str))
                results = cursor.fetchall()
                return results
    except Exception as e:
        logger.error(f"查询设备信息时出错: {e}")
        traceback.print_exc()


@mcp.tool()
async def get_device_runtime_data(tenant_id: int, device_name: str) -> list:
    """
    根据设备标识码，获取设备的所有属性最新的上报数据

    参数：
    tenant_id: 租户ID，用于区分数据权限
    device_name: 设备标识码

    返回:
    设备的属性列表，包含了查询到属性中所有属性的信息和最新上报数据
    包含的字段如下(括号中的是对应的数据库表的字段名)：
        设备标识码(deviceName)
        模块名称(moduleName)
        属性名称(propertyName)
        属性描述(propertyDescription)
        属性上报数据的单位(unit)
        属性的最新上报数据(current_value)
        属性上报数据的上报时间，字符串类型，已转换成用户的可读格式(report_time)
    """
    try:
        with DorisConnectionManager.get_connection() as conn:
            with conn.cursor() as cursor:
                sql = """
                SELECT
                    distinct 
                    deviceName,
                    moduleName,
                    propertyName,
                    propertyDescription,
                    unit,
                    current_value,
                    date_format(from_unixtime(report_time / 1000), '%%Y-%%m-%%d %%H:%%i:%%s') as report_time
                from
                    (
                    SELECT
                        deviceName,
                        moduleName,
                        propertyName,
                        propertyDescription,
                        unit,
                        first_value(value) over (
                    PARTITION by propertyName
                    order by
                        `timestamp` desc) as current_value,
                        first_value(`timestamp`) over (
                    PARTITION by propertyName
                    order by
                        `timestamp` desc) as report_time
                    from
                        `default`.property_data_all p
                    where
                        tenantId = %s
                        and deviceName = %s) as t
                order by
                    propertyName;
                """
                cursor.execute(sql, (tenant_id, device_name))
                results = cursor.fetchall()
                return results
    except Exception as e:
        logger.error(f"查询设备最新上报数据时出错: {e}")
        traceback.print_exc()


@mcp.tool()
async def get_property_history(tenant_id: int, device_name: str,
                               property_name: str, start_time: int, end_time: int) -> list:
    """
    获取设备属性历史数据

    参数：
    tenant_id: 租户ID，用于区分数据权限
    device_name: 设备标识码
    property_name: 属性名称
    start_time: 查询历史数据的开始时间，格式：时间戳(秒)
    end_time: 查询历史数据的结束时间，格式：时间戳(秒)

    返回:
    设备属性历史数据列表，包含的字段如下(括号中的是对应的数据库表的字段名)：
        模块名称(moduleName)
        属性名称(propertyName)
        属性描述(propertyDescription)
        属性上报数据的单位(unit)
        属性的上报数据(value)
        属性上报数据的上报时间，字符串类型，已转换成用户的可读格式(report_time)
    """
    try:
        with DorisConnectionManager.get_connection() as conn:
            with conn.cursor() as cursor:
                sql = f"""
                select
                    moduleName ,
                    propertyName ,
                    propertyDescription ,
                    unit ,
                    value,
                    date_format(from_unixtime(`timestamp` / 1000), '%%Y-%%m-%%d %%H:%%i:%%s') as report_time
                from
                    `default`.property_data_all
                where
                    tenantId = %s
                    and deviceName = %s
                    and (upper(propertyName) like upper(%s)
                        or upper(propertyDescription) like upper(%s))
                    and FLOOR(`timestamp`/1000) >= %s
                    and FLOOR(`timestamp`/1000) <= %s
                order by
                    `timestamp` asc
                limit 0,{MAX_DATA_SIZE}
                """
                param_str = f'%{property_name}%'
                cursor.execute(sql, (tenant_id, device_name, param_str, param_str, start_time, end_time))
                results = cursor.fetchall()
                return results
    except Exception as e:
        logger.error(f"获取设备属性历史数据时出错: {e}")
        traceback.print_exc()


@mcp.tool()
async def get_device_alarm(tenant_id: int, query_str: str) -> list:
    """
    获取设备待处理的告警

    参数：
    tenant_id: 租户ID，用于区分数据权限
    query_str: 搜索关键字,包括设备标识码、设备名称、设备编码、设备类型、设备描述等

    返回:
    设备属性历史数据列表，包含的字段如下(括号中的是对应的数据库表的字段名)：
        告警ID(alarmUUID)
        产品名称(productName)
        设备标识码(deviceName)
        设备名称(deviceDescription)
        告警值(alarmValue)
        告警级别，info：提示，warn：一般，error：严重(alarmLevel)
        告警类型， run：运行时告警，fault：故障告警(alarmType)
        告警内容(alarmContent)
        告警的上报时间，字符串类型，已转换成用户的可读格式(report_time)
    """
    try:
        with DorisConnectionManager.get_connection() as conn:
            with conn.cursor() as cursor:
                sql = f"""
                SELECT
                    alarmUUID ,
                    productName ,
                    deviceName,
                    deviceDescription ,
                    alarmValue,
                    alarmLevel,
                    alarmType,
                    alarmContent,
                    date_format(from_unixtime(alarmTimestamp / 1000), '%%Y-%%m-%%d %%H:%%i:%%s') as report_time
                from
                    `default`.rule_alarm
                where
                    tenantId = %s
                    and handleType is null
                    and (upper(deviceName) like upper(%s)
                        or upper(deviceDescription) like upper(%s)
                        or upper(productName) like upper(%s))
                order by
                    alarmTimestamp asc
                limit 0,{MAX_DATA_SIZE}
                """
                param_str = f'%{query_str}%'
                cursor.execute(sql, (tenant_id, param_str, param_str, param_str))
                results = cursor.fetchall()
                return results
    except Exception as e:
        logger.error(f"获取设备待处理的告警数据时出错: {e}")
        traceback.print_exc()


@mcp.tool()
async def get_device_status_history(tenant_id: int, device_name: str,
                                    start_time: int, end_time: int) -> list:
    """
    获取设备上下线的历史数据

    参数：
    tenant_id: 租户ID，用于区分数据权限
    device_name: 设备标识码
    start_time: 查询历史数据的开始时间，格式：时间戳(秒)
    end_time: 查询历史数据的结束时间，格式：时间戳(秒)

    返回:
    设备上下线历史数据列表，包含的字段如下(括号中的是对应的数据库表的字段名)：
        设备标识码(deviceName)
        本次上报的设备状态(deviceStatus)
        上一次上报的设备状态，可以用于判断状态的变化(lastStatus)
        状态变更累计时长，单位：秒(totalDuration)
        上报数据的时间，字符串类型，已转换成用户的可读格式(report_time)

    重要提醒：如果返回的历史数据为空，则代表设备这指定时间段内没有状态变化
    """
    try:
        with DorisConnectionManager.get_connection() as conn:
            with conn.cursor() as cursor:
                sql = f"""
                SELECT
                    deviceName ,
                    deviceStatus ,
                    lastStatus ,
                    FLOOR(totalDuration / 1000) as totalDuration ,
                    date_format(from_unixtime(`timestamp` / 1000), '%%Y-%%m-%%d %%H:%%i:%%s') as report_time
                from
                    `default`.device_status_all
                where
                    tenantId = %s
                    and `timestamp` is not null
                    and deviceName = %s
                    and FLOOR(`timestamp`/1000) >= %s
                    and FLOOR(`timestamp`/1000) <= %s
                order by
                    `timestamp` asc
                limit 0,{MAX_DATA_SIZE}
                """
                cursor.execute(sql, (tenant_id, device_name, start_time, end_time))
                results = cursor.fetchall()
                return results
    except Exception as e:
        logger.error(f"获取设备上下线的历史数据时出错: {e}")
        traceback.print_exc()


@mcp.tool()
async def confirm_alarm(auth_token: str, alarm_uuids: list,
                        handle_type: Literal["handle", "misreport", "noHandle"] = "handle",
                        handle_comment: str = "告警通过AI智能处理") -> str:
    """
    处理告警

    参数：
    auth_token: 用户登录的令牌
    alarm_uuids: 告警ID列表
    handle_type: 处理结果，结果只允许是以下的类型之一(括号中的是字段描述)：
        - handle(已处理)
        - misreport(误报)
        - noHandle(无需处理)
    handle_comment: 处理告警的备注描述
    """
    try:
        if len(alarm_uuids) == 0:
            return "未提供需要处理的告警"

        request_url = f"{get_ruge_settings('base_url')}/saascloud/saas/doris/rdata/alarm/confirmAlarm"
        request_headers = {
            "auth-token": auth_token
        }
        # 遍历处理每一个告警
        for uuid in alarm_uuids:
            params = {
                "alarmUUID": uuid,
                "handleType": handle_type,
                "handleComment": handle_comment
            }
            response = requests.post(url=request_url, headers=request_headers, json=params)
            response.raise_for_status()
        return "告警处理完成"
    except Exception as e:
        logger.error(f"处理告警时出错: {e}")
        traceback.print_exc()
        return "告警处理失败"


@mcp.tool()
async def get_device_inspection_rules() -> str:
    """
    获取设备巡检的规则说明

    返回:
    设备巡检的规则，包含了：
        1.是否需要巡检的判断条件
        2.检查的具体要求
        3.检查评定标准
        4.输出巡检报告的格式要求

    重要提醒：设备巡检是个严谨的工作，所以必须首先获取巡检规则，并遵循巡检规则执行，不可以臆想和编造巡检规则
    """
    return get_inspection_rules()
